﻿using IPlugin;
using IPlugin.Attributes;
using Mohe.Scada.Util.Models;
using NLog;
using OmronFinsTCP.Net;

namespace PLC.Omron
{
    [DriverSupported("OmronDriver")]
    [DriverInfo("OmronDriver", "V1.0.0", "湖州精确科技有限公司")]
    public class OmronDriver : IDriver
    {
        private EtherNetPLC _plc;
        private static Logger _logger = LogManager.GetLogger(nameof(OmronDriver));
        private readonly string _device;

        #region 配置参数

        [ConfigParameter("设备Id")]
        public int DeviceId { get; set; }

        [ConfigParameter("IP地址")]
        public string IpAddress { get; set; } = "127.0.0.1";

        [ConfigParameter("端口号")]
        public short Port { get; set; } = 6000;

        [ConfigParameter("超时时间ms")]
        public int TimeOut { get; set; } = 3000;

        [ConfigParameter("最小通讯周期ms")]
        public int MinPeriod { get; set; } = 3000;

        #endregion

        #region 生命周期

        /// <summary>
        /// 反射构造函数
        /// </summary>
        /// <param name="device"></param>
        /// <param name="logger"></param>
        public OmronDriver(string device)
        {
            _device = device;

            _logger.Info($"Device:[{_device}],Create()");
        }

        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected => _plc.IsConnected;

        /// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            try
            {
                _logger.Info($"Device:[{_device}],Connect()");

                _plc = new EtherNetPLC();
                _plc.Link(IpAddress, Port);

            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Device:[{_device}],Connect() Error");
                return false;
            }
            return IsConnected;
        }


        /// <summary>
        /// 断开
        /// </summary>
        /// <returns></returns>
        public bool Close()
        {
            try
            {
                _logger.Info($"Device:[{_device}],Close()");

                _plc?.Close();
                _plc = null;
                return !IsConnected;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Device:[{_device}],Close(),Error");
                return false;
            }
        }

        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {
            try
            {
                _logger.Info($"Device:[{_device}],Dispose()");

                // Suppress finalization.
                GC.SuppressFinalize(this);

            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Device:[{_device}],Dispose(),Error");
            }
        }
        #endregion

        #region 读写方法

        /// <summary>
        /// 读
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("读PLC标准地址", description: "读PLC标准地址")]
        public DriverReturnValueModel Read(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (_plc != null && this.IsConnected)
            {
                try
                {
                    switch (ioArg.ValueType)
                    {
                        //case EnumDataType.Bit:
                        //    ret.Value = _plc.GetBitState(PlcMemory.DM,ioArg.Address).Value == true ? 1 : 0;
                        //    break;
                        //case EnumDataType.Bool:
                        //    ret.Value = _plc.ReadBoolean(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.UByte:
                        //    ret.Value = _plc.Re(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Byte:
                        //    ret.Value = (sbyte)_plc.ReadByte(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Uint16:
                        //    ret.Value = _plc.ReadUInt16(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Int16:
                        //    ret.Value = _plc.ReadInt16(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Uint32:
                        //    ret.Value = _plc.ReadUInt32(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Int32:
                        //    ret.Value = _plc.ReadInt32(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Float:
                        //    ret.Value = _plc.ReadFloat(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Double:
                        //    ret.Value = _plc.ReadDouble(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Uint64:
                        //    ret.Value = _plc.ReadUInt64(ioArg.Address).Value;
                        //    break;
                        //case EnumDataType.Int64:
                        //    ret.Value = _plc.ReadInt64(ioArg.Address).Value;
                        //    break;

                        default:
                            ret.StatusType = EnumVariableStatus.Bad;
                            ret.Message = $"读取失败,不支持的类型:{ioArg.ValueType}";
                            break;
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }

        /// <summary>
        /// 写
        /// </summary>
        /// <param name="requestId"></param>
        /// <param name="method"></param>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        public async Task<RpcResponse> WriteAsync(string requestId, string method, DriverAddressIoArgModel ioArg)
        {
            RpcResponse rpcResponse = new() { IsSuccess = false, Description = "设备驱动内未实现写入功能" };
            await Task.CompletedTask;
            return rpcResponse;
        }
        #endregion

    }
}
